package com.example.shinelon.gobang.MyView;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.example.shinelon.gobang.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by DAB on 2016/4/3 16:14.
 */
public class GoBangView extends View {
    private int mPanelWidth;
    private float mLineHeight;
    private int MAX_LINE;
    private int MAX_NUM_WIN;
    private Paint paint = new Paint();

    private Bitmap mOnePiece;
    private Bitmap mTwoPiece;
    private int mChessLineColor;
    private int mChessBoardColor;
    private float mPieceSize = (3 * 1.0f) / 4;
    private ArrayList<Point> mOnePieceArray = new ArrayList<>();
    private ArrayList<Point> mTwoPieceArray = new ArrayList<>();
    private ArrayList<Point> mBackArray = new ArrayList<>();
    private boolean mIsOne = true;
    private boolean mIsEnd = false;
    private boolean mIsOneWin = false;

    public GoBangView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GoBangView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GoBangView, defStyleAttr, 0);
        for (int i = 0; i < array.length(); i++) {
            switch (i) {
                case R.styleable.GoBangView_onePiece:
                    mOnePiece = BitmapFactory.decodeResource(getResources(), array.getResourceId(i, R.mipmap.ic_launcher));
                    break;
                case R.styleable.GoBangView_twoPiece:
                    mTwoPiece = BitmapFactory.decodeResource(getResources(), array.getResourceId(i, R.mipmap.ic_launcher));
                    break;
                case R.styleable.GoBangView_chessLineColor:
                    mChessLineColor = array.getColor(i, Color.BLACK);
                    break;
                case R.styleable.GoBangView_chessBoardColor:
                    mChessBoardColor = array.getColor(i, getResources().getColor(R.color.colorPrimaryDark));
                    break;
                case R.styleable.GoBangView_chessBoardSize:
                    MAX_LINE = array.getInteger(i, 10);
                    break;
                case R.styleable.GoBangView_howMuchWin:
                    MAX_NUM_WIN = array.getInteger(i, 5);
                    break;
            }
        }
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        setBackgroundColor(mChessBoardColor);
        paint.setColor(mChessLineColor);
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.STROKE);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = Math.min(widthSize, heightSize);

        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize;
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize;
        }
        setMeasuredDimension(width, width);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mPanelWidth = w;
        mLineHeight = (mPanelWidth * 1.0f) / MAX_LINE;
        int mPieceWidth = (int) (mLineHeight * mPieceSize);
        mOnePiece = Bitmap.createScaledBitmap(mOnePiece, mPieceWidth, mPieceWidth, false);
        mTwoPiece = Bitmap.createScaledBitmap(mTwoPiece, mPieceWidth, mPieceWidth, false);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mIsEnd) {
            return false;
        }
        mBackArray.clear();
        if (event.getAction() == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            Point p = new Point((int) (x / mLineHeight), (int) (y / mLineHeight));

            if (mOnePieceArray.contains(p) || mTwoPieceArray.contains(p)) {
                return false;
            }
            if (mIsOne) {
                mOnePieceArray.add(p);
            } else {
                mTwoPieceArray.add(p);
            }
            invalidate();
            mIsOne = !mIsOne;

        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBoard(canvas);
        checkEnd();

        drawPieces(canvas);
    }

    public interface onWinChanged {
        void winChanged(boolean isOneWin);
    }

    private onWinChanged mOnWinChanged = null;

    public void setOnWinChanged(onWinChanged mOnWinChanged) {
        this.mOnWinChanged = mOnWinChanged;
    }

    /**
     * 检测是否分出胜负
     */
    private void checkEnd() {
        if (mOnePieceArray.size() > 1) {
            boolean oneWin = checkWin(mOnePieceArray);
            boolean twoWin = checkWin(mTwoPieceArray);
            if (oneWin || twoWin) {
                mIsEnd = true;
                mIsOneWin = oneWin;
                mOnWinChanged.winChanged(mIsOneWin);
            } else {
                mIsEnd = false;
            }
        }

    }

    private boolean checkWin(List<Point> pieceArray) {

        return checkHor(pieceArray) || checkVer(pieceArray)
                || checkLiftPos(pieceArray) || checkRightPos(pieceArray);
    }

    /**
     * 检测是否右斜方向形成5个棋子
     *
     * @param pieceArray
     * @return
     */
    private boolean checkRightPos(List<Point> pieceArray) {
        Point lastPoint = pieceArray.get(pieceArray.size() - 1);
        int count = 1;
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x + i, lastPoint.y - i))) {
                count++;
            } else {
                break;
            }
        }
        if (count >= MAX_NUM_WIN) {
            return true;
        }
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x - i, lastPoint.y + i))) {
                count++;
            } else {
                break;
            }
        }
        return count >= MAX_NUM_WIN;
    }

    /**
     * 检测是否左斜方向形成5个棋子
     *
     * @param pieceArray
     * @return
     */
    private boolean checkLiftPos(List<Point> pieceArray) {
        Point lastPoint = pieceArray.get(pieceArray.size() - 1);
        int count = 1;
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x - i, lastPoint.y - i))) {
                count++;
            } else {
                break;
            }
        }
        if (count >= MAX_NUM_WIN) {
            return true;
        }
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x + i, lastPoint.y + i))) {
                count++;
            } else {
                break;
            }
        }
        return count >= MAX_NUM_WIN;
    }

    /**
     * 检测是否纵向形成5个棋子
     *
     * @param pieceArray
     * @return
     */
    private boolean checkVer(List<Point> pieceArray) {
        Point lastPoint = pieceArray.get(pieceArray.size() - 1);
        int count = 1;
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x, lastPoint.y - i))) {
                count++;
            } else {
                break;
            }
        }
        if (count >= MAX_NUM_WIN) {
            return true;
        }
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x, lastPoint.y + i))) {
                count++;
            } else {
                break;
            }
        }
        return count >= MAX_NUM_WIN;
    }

    /***
     * 检测是否横向形成5个棋子
     *
     * @param pieceArray
     * @return
     */
    private boolean checkHor(List<Point> pieceArray) {
        Point lastPoint = pieceArray.get(pieceArray.size() - 1);
        int count = 1;
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x - i, lastPoint.y))) {
                count++;
            } else {
                break;
            }
        }
        if (count >= MAX_NUM_WIN) {
            return true;
        }
        for (int i = 1; i < MAX_NUM_WIN; i++) {
            if (pieceArray.contains(new Point(lastPoint.x + i, lastPoint.y))) {
                count++;
            } else {
                break;
            }
        }
        return count >= MAX_NUM_WIN;
    }

    /**
     * 根据集合里的数据画棋子
     *
     * @param canvas
     */
    private void drawPieces(Canvas canvas) {

        for (int i = 0; i < mOnePieceArray.size(); i++) {
            Point onePiece = mOnePieceArray.get(i);
            canvas.drawBitmap(toCircleBitmap(mOnePiece),
                    (onePiece.x + 1f / 8) * mLineHeight,
                    (onePiece.y + 1f / 8) * mLineHeight, null);
//            canvas.drawBitmap(mOnePiece,
//                    (onePiece.x + (1 / 2) - ((3 / 4) * 1 / 2)) * mLineHeight,
//                    (onePiece.y + (1 / 2) - ((3 / 4) * 1 / 2)) * mLineHeight, null);
        }
        for (int i = 0; i < mTwoPieceArray.size(); i++) {
            Point twoPiece = mTwoPieceArray.get(i);

            canvas.drawBitmap(toCircleBitmap(mTwoPiece),
                    (twoPiece.x + 1f / 8) * mLineHeight,
                    (twoPiece.y + 1f / 8) * mLineHeight, null);

        }
    }

    /**
     * 画棋盘
     *
     * @param canvas
     */
    private void drawBoard(Canvas canvas) {
        int w = mPanelWidth;
        float lineheight = mLineHeight;
        for (int i = 0; i < MAX_LINE; i++) {
            int startX = (int) (lineheight / 2);
            int stopX = (int) (w - lineheight / 2);
            int y = (int) ((0.5 + i) * lineheight);
            canvas.drawLine(startX, y, stopX, y, paint);
            canvas.drawLine(y, startX, y, stopX, paint);
        }
    }


    /**
     * 将图片转换成圆形图片显示
     */
    public Bitmap toCircleBitmap(Bitmap source) {
        int min = Math.min(source.getWidth(), source.getHeight());
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
        /**
         * 产生一个同样大小的画布
         */
        Canvas canvas = new Canvas(target);
        /**
         * 首先绘制圆形
         */
        canvas.drawCircle(min / 2, min / 2, min / 2, paint);
        /**
         * 使用SRC_IN
         */
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        /**
         * 绘制图片
         */
        canvas.drawBitmap(source, 0, 0, paint);
        return target;
    }


    private static final String KEY_GAME_OVER = "game_over";
    private static final String KEY_INSTANCE = "instance";
    private static final String KEY_ONE_ARRAY = "one_array";
    private static final String KEY_TWO_ARRAY = "two_array";

    /**
     * 切换屏幕的时候,保存一些状态,数据
     *
     * @return
     */
    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(KEY_INSTANCE, super.onSaveInstanceState());
        bundle.putBoolean(KEY_GAME_OVER, mIsEnd);
        bundle.putParcelableArrayList(KEY_ONE_ARRAY, mOnePieceArray);
        bundle.putParcelableArrayList(KEY_TWO_ARRAY, mTwoPieceArray);
        return bundle;
    }

    /**
     * 恢复保存的数据
     *
     * @param state
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            mIsEnd = bundle.getBoolean(KEY_GAME_OVER);
            mOnePieceArray = bundle.getParcelableArrayList(KEY_ONE_ARRAY);
            mTwoPieceArray = bundle.getParcelableArrayList(KEY_TWO_ARRAY);
            super.onRestoreInstanceState(bundle.getParcelable(KEY_INSTANCE));
            return;
        }
        super.onRestoreInstanceState(state);
    }

    /**
     * 返回上一步
     *
     * @return
     */
    public Boolean undo() {

        if ((mOnePieceArray.size() - 1 < 0) || (mTwoPieceArray.size() - 1 < 0)) {
            return false;
        } else {
            mBackArray.add(mOnePieceArray.get(mOnePieceArray.size() - 1));
            mBackArray.add(mTwoPieceArray.get(mTwoPieceArray.size() - 1));
            mOnePieceArray.remove(mOnePieceArray.size() - 1);
            mTwoPieceArray.remove(mTwoPieceArray.size() - 1);
            checkEnd();
            invalidate();
            return true;
        }

    }

    /**
     * 下一步
     *
     * @return
     */
    public boolean nextStep() {
        if (mBackArray.size() - 1 < 0) {
            return false;
        } else {
            if (mIsOne) {
                nextTwo();
                nextOne();
            } else {
                nextTwo();
                nextOne();
            }
            invalidate();
            return true;
        }
    }

    private void nextOne() {
        mOnePieceArray.add(mBackArray.get(mBackArray.size() - 1));
        mBackArray.remove(mBackArray.size() - 1);
    }

    private void nextTwo() {
        mTwoPieceArray.add(mBackArray.get(mBackArray.size() - 1));
        mBackArray.remove(mBackArray.size() - 1);
    }

    /**
     * 重新开始
     */
    public void restart() {
        mOnePieceArray.clear();
        mTwoPieceArray.clear();
        mIsEnd = false;
        mIsOneWin = false;
        invalidate();
    }

}
